package com.gitee.wsl.text.format

import com.gitee.wsl.ext.number.format
import com.gitee.wsl.ext.string.EMPTY
import com.gitee.wsl.ext.string.reverse
import kotlin.jvm.JvmOverloads


/**
 * 将浮点数类型的number转换成英语的表达方式 <br></br>
 * 参考博客：http://blog.csdn.net/eric_sunah/article/details/8713226<br></br>
 * 本质上此类为金额转英文表达，因此没有四舍五入考虑，小数点超过两位直接忽略。
 *
 * @author Looly,totalo
 * @since 3.0.9
 */
object NumberWordFormatter {
    private val NUMBER = arrayOf<String>(
        "", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN",
        "EIGHT", "NINE"
    )
    private val NUMBER_TEEN = arrayOf<String>(
        "TEN", "ELEVEN", "TWELVE", "THIRTEEN", "FOURTEEN",
        "FIFTEEN", "SIXTEEN", "SEVENTEEN", "EIGHTEEN", "NINETEEN"
    )
    private val NUMBER_TEN = arrayOf<String>(
        "TEN", "TWENTY", "THIRTY", "FORTY", "FIFTY", "SIXTY",
        "SEVENTY", "EIGHTY", "NINETY"
    )
    private val NUMBER_MORE = arrayOf<String>("", "THOUSAND", "MILLION", "BILLION", "TRILLION")

    private val NUMBER_SUFFIX = arrayOf<String>("k", "w", "m", "b", "t", "p", "e")

    // 标准单位序列(k, m, b, t, p, e)在NUMBER_SUFFIX中的索引
    private val STANDARD_UNIT_INDICES = intArrayOf(0, 2, 3, 4, 5, 6)

    /**
     * 将阿拉伯数字转为英文表达式
     *
     * @param x 阿拉伯数字，可以为[Number]对象，也可以是普通对象，最后会使用字符串方式处理
     * @return 英文表达式
     */
    fun format(x: Any?): String {
        if (x != null) {
            return NumberWordFormatter.format(x.toString())
        } else {
            return String.EMPTY
        }
    }

    /**
     * 将阿拉伯数字转化为简介计数单位，例如 2100 =》 2.1k
     *
     * @param value 对应数字的值
     * @param isTwo 控制是否为只为k、w，例如当为`false`时返回4.38m，`true`返回438.43w
     * @return 格式化后的数字
     * @since 5.5.9
     */
    /**
     * 将阿拉伯数字转化为简洁计数单位，例如 2100 =》 2.1k
     * 范围默认只到w
     *
     * @param value 被格式化的数字
     * @return 格式化后的数字
     * @since 5.5.9
     */
    @JvmOverloads
    fun formatSimple(value: Long, isTwo: Boolean = true): String? {
        if (value < 1000) {
            return value.toString()
        }

        var res = value.toDouble()
        val index: Int

        if (isTwo) {
            // 当isTwo为true时，只使用k和w单位
            if (value >= 10000) {
                // 使用w单位（除以10000，即10k = 1w）
                res = value / 10000.0
                index = 1 // w在NUMBER_SUFFIX[1]
            } else {
                // 使用k单位（除以1000）
                res = value / 1000.0
                index = 0 // k在NUMBER_SUFFIX[0]
            }
        } else {
            // 当isTwo为false时，使用标准单位序列 (k, m, b, t, p, e)
            // 对应NUMBER_SUFFIX中的索引为 0, 2, 3, 4, 5, 6
            var unitIndex = -1
            while (res >= 1000 && unitIndex < STANDARD_UNIT_INDICES.size - 1) {
                res = res / 1000
                unitIndex++
            }
            index = STANDARD_UNIT_INDICES[unitIndex]
        }

        return String.format("%s%s", res.format(2), NUMBER_SUFFIX[index])
    }

    /**
     * 将阿拉伯数字转为英文表达式
     *
     * @param x 阿拉伯数字字符串
     * @return 英文表达式
     */
    private fun format(x: String): String {
        val z = x.indexOf(".") // 取小数点位置
        val lstr: String
        var rstr = ""
        if (z > -1) { // 看是否有小数，如果有，则分别取左边和右边
            lstr = x.substring(0, z)
            rstr = x.substring(z + 1)
        } else {
            // 否则就是全部
            lstr = x
        }

        var lstrrev: String = lstr.reverse() // 对左边的字串取反
        val a = kotlin.arrayOfNulls<String>(5) // 定义5个字串变量来存放解析出来的叁位一组的字串

        when (lstrrev.length % 3) {
            1 -> lstrrev += "00"
            2 -> lstrrev += "0"
        }
        var lm = StringBuilder() // 用来存放转换后的整数部分
        for (i in 0..<lstrrev.length / 3) {
            a[i] = lstrrev.substring(3 * i, 3 * i + 3).reverse() // 截取第一个三位
            if ("000" != a[i]) { // 用来避免这种情况：1000000 = one million
                // thousand only
                if (i != 0) {
                    lm.insert(0, transThree(a[i]!!) + " " + parseMore(i) + " ") // 加:
                    // thousand、million、billion
                } else {
                    // 防止i=0时， 在多加两个空格.
                    lm = StringBuilder(transThree(a[i]!!))
                }
            } else {
                lm.append(NumberWordFormatter.transThree(a[i]!!))
            }
        }

        var xs = if (lm.isEmpty()) "ZERO " else " " // 用来存放转换后小数部分
        if (z > -1) {
            xs += "AND CENTS " + transTwo(rstr) + " " // 小数部分存在时转换小数
        }

        return lm.toString().trim { it <= ' ' } + xs + "ONLY"
    }

    private fun parseTeen(s: String): String {
        return NUMBER_TEEN[s.toInt() - 10]
    }

    private fun parseTen(s: String): String {
        return NUMBER_TEN[s.substring(0, 1).toInt() - 1]
    }

    private fun parseMore(i: Int): String {
        return NUMBER_MORE[i]
    }

    // 两位
    private fun transTwo(s: String): String {
        var s = s
        val value: String
        // 判断位数
        if (s.length > 2) {
            s = s.substring(0, 2)
        } else if (s.length < 2) {
            s = s + "0"
        }

        if (s.startsWith("0")) { // 07 - seven 是否小於10
            value = parseLast(s)
        } else if (s.startsWith("1")) { // 17 seventeen 是否在10和20之间
            value = parseTeen(s)
        } else if (s.endsWith("0")) { // 是否在10与100之间的能被10整除的数
            value = parseTen(s)
        } else {
            value = parseTen(s) + " " + parseLast(s)
        }
        return value
    }

    // 制作叁位的数
    // s.length = 3
    private fun transThree(s: String): String {
        val value: String
        if (s.startsWith("0")) { // 是否小於100
            value = transTwo(s.substring(1))
        } else if ("00" == s.substring(1)) { // 是否被100整除
            value = parseLast(s.substring(0, 1)) + " HUNDRED"
        } else {
            value = parseLast(s.substring(0, 1)) + " HUNDRED AND " + transTwo(s.substring(1))
        }
        return value
    }

    private fun parseLast(s: String): String {
        return NUMBER[s.substring(s.length - 1).toInt()]
    }
}
